#include <assert.h>
#include <cstdlib>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

#include "yuv2rgb.h"

int check_data(int data[RGB_NUM][DCTSIZE2], int ref[RGB_NUM][DCTSIZE2]) {
    int has_errors = 0;

    for (int i = 0; i < DCTSIZE2; i++) {
        int flag = 0;
        if (data[0][i] != ref[0][i] ||
            data[1][i] != ref[1][i] ||
            data[2][i] != ref[2][i]) {
            has_errors = 1;
        }
    }

    return !has_errors;
}

char *readfile(int fd) {
    char *p;
    struct stat s;
    off_t len;
    ssize_t bytes_read, status;

    assert(fd > 1 && "Invalid file descriptor");
    assert(0 == fstat(fd, &s) && "Couldn't determine file size");
    len = s.st_size;
    assert(len > 0 && "File is empty");
    p = (char *)malloc(len + 1);
    bytes_read = 0;
    while (bytes_read < len) {
        status = read(fd, &p[bytes_read], len - bytes_read);
        assert(status >= 0 && "read() failed");
        bytes_read += status;
    }
    p[len] = (char)0;
    close(fd);
    return p;
}

int main() {
    char *in_file = "input.data";
    char *check_file = "check.data";

    int in_fd = open(in_file, O_RDONLY);
    assert(in_fd > 0 && "Couldn't open input data file");
    char *data = readfile(in_fd);

    int y_buf[DCTSIZE2];
    int u_buf[DCTSIZE2];
    int v_buf[DCTSIZE2];

    // output buffer
    int rgb_buf[4][RGB_NUM][DCTSIZE2] = {0};
    int rgb_ref[4][RGB_NUM][DCTSIZE2] = {0};

    int i = 0;
    char *line = data;
    while (i < DCTSIZE2 && line) {
        int y, u, v;
        int n;
        if (sscanf(line, "%d %d %d%n", &y, &u, &v, &n) == 3) {
            y_buf[i] = y;
            u_buf[i] = u;
            v_buf[i] = v;
            i++;
            line += n;
        }
    }

    YuvToRgb(0, y_buf, u_buf, v_buf, rgb_buf);

    int check_fd = open("check.data", O_RDONLY);
    assert(check_fd > 0 && "Couldn't open check data file");
    char *ref = readfile(check_fd);

    i = 0; line = ref;
    while (i < DCTSIZE2 && line) {
        int r, g, b;
        int n;
        if (sscanf(line, "%d %d %d%n", &r, &g, &b, &n) == 3) {
            rgb_ref[0][0][i] = r;
            rgb_ref[0][1][i] = g;
            rgb_ref[0][2][i] = b;
            i++;
            line += n;
        }
    }

    if (!check_data(rgb_buf[0], rgb_ref[0])) {
        fprintf(stderr, "Benchmark results are incorrect\n");
        return -1;
    }

    free(data);
    free(ref);

    printf("Success.\n");

    return 0;
}
